/*
 * Copyright (C) 2012 mAPPn.Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.mol.market.common.network;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.Iterator;
import java.util.zip.GZIPInputStream;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.text.TextUtils;

import com.mol.market.common.util.Utils;

/**
 * HTTP Connection Manager.
 * <p/>
 * Author: Andrew.Wang
 * Date  : 12-9-26
 */
public class HttpConnectionManager {

    private static HttpConnectionManager sInstance;

    /**
     * Application Context
     */
    private Context mContext;

    private HttpConnectionManager(Context ctx) {
        mContext = ctx;
        disableConnectionReuseIfNecessary();
    }

    public synchronized static HttpConnectionManager get(Context ctx) {

        if (sInstance == null) {
            sInstance = new HttpConnectionManager(ctx);
        }
        return sInstance;
    }

    /**
     * Create new http url connection.
     * <p/>
     * <p/>
     * 1. Default use GZip compress
     * 2. Use system default proxy
     */

    public ApiResponse execute(HttpURLConnection connection, ApiRequest request)
        throws IOException {

        writeStream(request.requestBody, connection.getOutputStream());

        return readResponse(request.actionId, connection);
    }


    public HttpURLConnection buildConnection(ApiRequest request) throws IOException {

        URL url = new URL(request.url);
        HttpURLConnection connection =
            (HttpURLConnection) url.openConnection(detectProxy(mContext));

        if (!url.getHost().equals(connection.getURL().getHost())) {
            // TODO we were redirected! Kick the user out to the browser to sign on?
            throw new IOException("please sign on your network...");
        }

        // add request headers
        Bundle headers = request.requestHeader;
        Iterator<String> keys = headers.keySet().iterator();
        while (keys.hasNext()) {
            String key = keys.next();
            connection.addRequestProperty(key, headers.getString(key));
        }

        // detect to use which request method
        if (ApiRequest.POST == request.requestMethod) {
            connection.setDoOutput(true);
            connection.setChunkedStreamingMode(0);

        } else if (ApiRequest.GET == request.requestMethod) {

            
        }
        // do nothing
        connection.connect();

        return connection;
    }

    /**
     * 检查Proxy
     * TODO performance
     */
    public static Proxy detectProxy(Context context) {
        ConnectivityManager cm = (ConnectivityManager)
            context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo ni = cm.getActiveNetworkInfo();
        if (ni != null && ni.isAvailable()
            && ni.getType() == ConnectivityManager.TYPE_MOBILE) {
            String proxyHost = android.net.Proxy.getDefaultHost();
            int port = android.net.Proxy.getDefaultPort();
            if (proxyHost != null) {
                return new Proxy(Proxy.Type.HTTP,
                    new InetSocketAddress(proxyHost, port));
            }
        }
        return Proxy.NO_PROXY;
    }

    /**
     * HTTP connection reuse which was buggy pre-froyo
     */
    private void disableConnectionReuseIfNecessary() {
//        if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
            System.setProperty("http.keepAlive", "false");
//        }
    }

    /**
     * Write http request OutputStream
     *
     * @param content
     * @param os
     * @throws IOException
     */
    private static void writeStream(String content, OutputStream os)
        throws IOException {

        BufferedOutputStream bos = new BufferedOutputStream(os);
        byte[] bytes = content.getBytes(Utils.ENCODING_UTF8);
        bos.write(bytes);
        bos.flush();
        bos.close();
    }

    /**
     * @param connection
     * @return
     * @throws IOException
     */

    private static ApiResponse readResponse(int actionCode,
        HttpURLConnection connection) throws IOException {

        ApiResponse response = new ApiResponse(actionCode, connection.getResponseCode());

        if (response.status != HttpURLConnection.HTTP_OK) {
            return response;
        }

        String contentEncoding = connection.getContentEncoding();
        InputStream input;
        if (TextUtils.isEmpty(contentEncoding)) {
            input = connection.getInputStream();
        } else {
            input = new GZIPInputStream(connection.getInputStream());
        }

        response.content = input;
        response.charset = Utils.getContentCharSet(connection);
        return response;
    }
}
